import React, { useEffect, useState } from 'react';
import { Connection, PublicKey, clusterApiUrl, LAMPORTS_PER_SOL } from '@solana/web3.js';
import { Program, AnchorProvider, web3, utils, BN } from '@project-serum/anchor';
import { getAssociatedTokenAddress } from '@solana/spl-token';
import { Wallet, Info, Coins } from 'lucide-react';
import toast, { Toaster } from 'react-hot-toast';

// Local IDL definition as fallback
const localIdl = {
  "version": "0.1.0",
  "name": "token_sale",
  "instructions": [
    {
      "name": "buyTokens",
      "accounts": [
        {
          "name": "ico",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "contractTokenAccount",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "userTokenAccount",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "solReceiver",
          "isMut": true,
          "isSigner": false
        },
        {
          "name": "user",
          "isMut": true,
          "isSigner": true
        },
        {
          "name": "tokenProgram",
          "isMut": false,
          "isSigner": false
        },
        {
          "name": "systemProgram",
          "isMut": false,
          "isSigner": false
        },
        {
          "name": "signer",
          "isMut": false,
          "isSigner": false
        },
        {
          "name": "tokenMint",
          "isMut": false,
          "isSigner": false
        }
      ],
      "args": [
        {
          "name": "amount",
          "type": "u64"
        }
      ]
    }
  ]
};

// Contract constants
const CONTRACT_PARAMS = {
  icoPDA: new PublicKey("DV1wFKTmBh8gBzgpbkZpd3msZZ1Z2MNojarz1x3FjCEC"),
  programId: new PublicKey("BLJWGTCo2ePjmfs9zf4Adi5tFGTwaKCVQWJ9nhqLEJm1"),
  solReceiver: new PublicKey("Bej7iASHNDpWcDcrDbv78yR9MCrYt1Cidcs8ksps4cwD"),
  mint: new PublicKey("3AW5ijSzMQ9KdjBPwizMfkudrFSHUN9mNP21nbLdYU4o"),
  tokenPrice: 1,
  remainingTokens: 99,
};

type PhantomEvent = "disconnect" | "connect" | "accountChanged";

interface ConnectorProps {
  children: React.ReactNode;
}

interface PhantomProvider {
  connect: () => Promise<{ publicKey: PublicKey }>;
  disconnect: () => Promise<void>;
  on: (event: PhantomEvent, callback: (args: any) => void) => void;
  isPhantom: boolean;
}

type WindowWithSolana = Window & {
  solana?: PhantomProvider;
}

function App() {
  const [walletAddress, setWalletAddress] = useState<string | null>(null);
  const [provider, setProvider] = useState<PhantomProvider | null>(null);
  const [solAmount, setSolAmount] = useState<string>("1");
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    if ("solana" in window) {
      const solWindow = window as WindowWithSolana;
      if (solWindow?.solana?.isPhantom) {
        setProvider(solWindow.solana);
        solWindow.solana.connect({ onlyIfTrusted: true });
      }
    }
  }, []);

  useEffect(() => {
    if (provider) {
      provider.on('connect', (publicKey: PublicKey) => {
        console.log('Connected to wallet ' + publicKey.toBase58());
        setWalletAddress(publicKey.toBase58());
        toast.success('Wallet connected!');
      });

      provider.on('disconnect', () => {
        console.log('Disconnected from wallet');
        setWalletAddress(null);
        toast.error('Wallet disconnected!');
      });
    }
  }, [provider]);

  const connectWallet = async () => {
    try {
      if (!provider) {
        toast.error('Please install Phantom wallet first!');
        window.open('https://phantom.app/', '_blank');
        return;
      }

      toast.loading('Please approve the connection request in your Phantom wallet...', {
        duration: 6000,
      });

      const { publicKey } = await provider.connect();
      setWalletAddress(publicKey.toBase58());
    } catch (err) {
      console.error("Error connecting to wallet:", err);
      if (err.message.includes('User rejected')) {
        toast.error('Connection request was declined. Please try again and approve the connection in your Phantom wallet.');
      } else {
        toast.error('Failed to connect wallet. Please try again.');
      }
    }
  };

  const disconnectWallet = async () => {
    try {
      if (provider) {
        await provider.disconnect();
        setWalletAddress(null);
      }
    } catch (err) {
      console.error("Error disconnecting from wallet:", err);
      toast.error('Failed to disconnect wallet');
    }
  };

  const signMessage = async () => {
    try {
      if (!provider || !walletAddress) {
        throw new Error('Wallet not connected');
      }

      const message = new TextEncoder().encode('Hello, Solana!');
      const connection = new Connection(clusterApiUrl('devnet'));
      const anchorProvider = new AnchorProvider(
        connection,
        provider as any,
        { commitment: 'processed' }
      );

      const signature = await anchorProvider.wallet.signMessage(message);
      console.log('Message signed:', signature);
      toast.success('Message signed successfully!');
    } catch (err) {
      console.error("Error signing message:", err);
      toast.error('Failed to sign message');
    }
  };

  const buyTokens = async () => {
    if (!provider || !walletAddress) {
      toast.error('Please connect your wallet first');
      return;
    }

    setIsLoading(true);
    const toastId = toast.loading('Processing your purchase...');

    try {
      const connection = new Connection(clusterApiUrl('devnet'));
      const anchorProvider = new AnchorProvider(
        connection,
        provider as any,
        { commitment: 'processed' }
      );

      // Get contract token account (ATA)
      const contractTokenAccount = await getAssociatedTokenAddress(
        CONTRACT_PARAMS.mint,
        CONTRACT_PARAMS.icoPDA,
        true // allowOwnerOffCurve
      );
      console.log('Contract Token Account:', contractTokenAccount.toBase58());

      // Get user token account (ATA)
      const userTokenAccount = await getAssociatedTokenAddress(
        CONTRACT_PARAMS.mint,
        new PublicKey(walletAddress)
      );
      console.log('User Token Account:', userTokenAccount.toBase58());

      let idl = localIdl;

      // try {
      //   idl = await Program.fetchIdl(CONTRACT_PARAMS.programId, anchorProvider);
      // } catch (err) {
      //   console.log('Failed to fetch IDL, using local IDL instead');
      //   console.error(err); // 打印错误详情
      //   idl = localIdl;
      // }

      // console.log(idl, 'IDL');

      // if (!idl) {
      //   throw new Error('No IDL available');
      // }

      const program = new Program(idl, CONTRACT_PARAMS.programId, anchorProvider);

      const solAmountLamports = new BN(parseFloat(solAmount) * LAMPORTS_PER_SOL);

      const tx = await program.methods
        .buyTokens(solAmountLamports)
        .accounts({
          ico: CONTRACT_PARAMS.icoPDA,
          contractTokenAccount: contractTokenAccount,
          userTokenAccount: userTokenAccount,
          solReceiver: CONTRACT_PARAMS.solReceiver,
          user: new PublicKey(walletAddress),
          tokenProgram: utils.token.TOKEN_PROGRAM_ID,
          systemProgram: web3.SystemProgram.programId,
          signer: CONTRACT_PARAMS.solReceiver,
          tokenMint: CONTRACT_PARAMS.mint,
        })
        .rpc();

      console.log('Transaction signature:', tx);
      toast.success('Tokens purchased successfully!', { id: toastId });
    } catch (err) {
      console.error('Error buying tokens:', err);
      toast.error(err.message || 'Failed to purchase tokens', { id: toastId });
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-purple-900 to-blue-900 text-white">
      <Toaster position="top-right" />
      <div className="container mx-auto px-4 py-8">
        <div className="max-w-2xl mx-auto">
          <div className="bg-white/10 backdrop-blur-lg rounded-xl p-8 shadow-xl">
            <div className="flex items-center justify-between mb-8">
              <h1 className="text-3xl font-bold flex items-center gap-2">
                <Wallet className="w-8 h-8" />
                Solana dApp
              </h1>
              {!walletAddress ? (
                <button
                  onClick={connectWallet}
                  className="bg-purple-500 hover:bg-purple-600 text-white px-6 py-2 rounded-lg transition-colors"
                >
                  Connect Wallet
                </button>
              ) : (
                <button
                  onClick={disconnectWallet}
                  className="bg-red-500 hover:bg-red-600 text-white px-6 py-2 rounded-lg transition-colors"
                >
                  Disconnect
                </button>
              )}
            </div>

            {!walletAddress && (
              <div className="bg-blue-500/20 rounded-lg p-4 mb-6 flex items-start gap-3">
                <Info className="w-5 h-5 mt-0.5 flex-shrink-0" />
                <div>
                  <h3 className="font-semibold mb-1">Why connect a wallet?</h3>
                  <p className="text-sm text-gray-300">
                    Connecting your Phantom wallet allows you to interact with the Solana blockchain,
                    sign messages, and perform transactions. When prompted, please approve the
                    connection request in your Phantom wallet extension.
                  </p>
                </div>
              </div>
            )}

            {walletAddress && (
              <div className="space-y-6">
                <div className="bg-white/5 rounded-lg p-4">
                  <h2 className="text-sm text-gray-300 mb-2">Connected Wallet</h2>
                  <p className="font-mono text-sm break-all">{walletAddress}</p>
                </div>

                <div className="bg-white/5 rounded-lg p-4">
                  <h2 className="text-sm text-gray-300 mb-2">Buy Tokens</h2>
                  <div className="space-y-4">
                    <div>
                      <label htmlFor="solAmount" className="block text-sm font-medium text-gray-300 mb-1">
                        SOL Amount
                      </label>
                      <input
                        type="number"
                        id="solAmount"
                        value={solAmount}
                        onChange={(e) => setSolAmount(e.target.value)}
                        min="0.1"
                        step="0.1"
                        className="w-full bg-white/5 border border-white/10 rounded-lg px-4 py-2 text-white"
                        placeholder="Enter SOL amount"
                      />
                    </div>
                    <button
                      onClick={buyTokens}
                      disabled={isLoading}
                      className="w-full bg-green-500 hover:bg-green-600 disabled:bg-green-500/50 disabled:cursor-not-allowed text-white px-6 py-3 rounded-lg transition-colors flex items-center justify-center gap-2"
                    >
                      <Coins className="w-5 h-5" />
                      {isLoading ? 'Processing...' : 'Buy Tokens'}
                    </button>
                  </div>
                </div>

                <button
                  onClick={signMessage}
                  className="w-full bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg transition-colors"
                >
                  Sign Message
                </button>

                <div className="bg-white/5 rounded-lg p-4">
                  <h2 className="text-sm text-gray-300 mb-2">Network</h2>
                  <p className="font-mono text-sm">Solana Devnet</p>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

export default App;